package com.opentd.game;

import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Vector;

import javax.swing.JOptionPane;

import com.opentd.files.LevelManager;
import com.opentd.graphics.Level;
import com.opentd.graphics.PaintLoop;
import com.opentd.graphics.screen.EndScreen;
import com.opentd.graphics.screen.GameScreen;
import com.opentd.graphics.screen.LevelSelectScreen;
import com.opentd.graphics.screen.MainScreen;
import com.opentd.gui.GamePanel;

/**
 * 
 * @author Nathan Hoyt
 * Date: Oct 25, 2012
 * Desc: This class holds all of the global variables and constants used throughout
 * the program.
 */
public class Game {
	/**
	 * Title for the JFrame.
	 */
	public static final String TITLE = "Open TD - Open Source Java Tower Defence";
	
	/**
	 * The panel to draw the game screen on.
	 */
	public static GamePanel panel;
	
	/**
	 * The game loop object that controls the game logic.
	 */
	public static GameLoop logicLoop;
	
	/**
	 * The paint loop object that controls the painting.
	 */
	public static PaintLoop paintLoop;
	
	/**
	 * Boolean to tell if the game is finished or not.
	 */
	public static boolean finished = false;
	
	/**
	 * Boolean to tell if the game is paused or not.
	 */
	public static boolean paused = false;
	
	/**
	 * The point representing the current mouse position.
	 */
	public static Point mousePos;
	
	/**
	 * The mouse mostion listener object to for the game. Use to add to a component.
	 */
	public static MouseMotion mouseMotionListener;
	
	/**
	 * The mouse listener object to for the game. Use to add to a component.
	 */
	public static MouseListen mouseListener;
	
	/**
	 * All of the levels that were loaded at startup of the program.
	 */
	public static Vector<Level> levels = new Vector<Level>();
	
	/**
	 * The currently selected level.
	 */
	public static Level selectedLevel = null;
	
	/**
	 * The currently selected level's index.
	 */
	public static int selectedLevelIndex = -1;
	
	/**
	 * The speed (0 - 100) of the moving NPC's
	 */
	public static final int NPC_MOVE_SPEED = 90;
	
	/**
	 * The FPS of the game. Used when calculating how long to sleep in-between game
	 */
	public static int FPS = 100;
	
	
	/**
	 * Initializes all non-final variables in the Game class and all subclasses.
	 */
	public static void init(){
		LevelManager.loadLevels("dat/lvl");
		logicLoop = new GameLoop();
		paintLoop = new PaintLoop();
		panel = new GamePanel();
		mousePos = new Point(0, 0);
		mouseListener = new MouseListen();
		mouseMotionListener = new MouseMotion();
		
		State.currentScreen = State.MAIN_SCREEN;
	}
	
	/**
	 * Quits the game, and if prompt is true, it will ask the user if they
	 * really want to exit. Pass true to prompt when a quit button is clicked
	 * so that the user is sure they want to quit. Pass false to this method
	 * if the game is being ended because of an error.
	 * @param prompt Whether or not to ask the user if they really want to quit.
	 */
	public static void exit(boolean prompt){
		if(prompt){
			int opCode = JOptionPane.showConfirmDialog(panel, "Are you sure you want to quit " + TITLE, "Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
			if(opCode == JOptionPane.NO_OPTION)
				return;
		}
		GameLoop.exit();
	}
	
	/**
	 * 
	 * @author Nathan Hoyt
	 * Date: Oct 25, 2012
	 * Desc: Nested <b>Block</b> class that will hold all of the constants and
	 * global variables used for creation, calculation, drawing, and editing blocks
	 *
	 */
	public static class Block {
		public static final int GRASS_BLOCK_ID = 0;
		public static final int PATH_BLOCK_ID = 1;
		public static final int SAND_BLOCK_ID = 2;
		public static final int FINISH_BLOCK_ID = 3;
		
		public static final int WIDTH = 50;
		public static final int HEIGHT = 50;
	}
	
	/**
	 * 
	 * @author Nathan Hoyt
	 * Date: Oct 25, 2012
	 * Desc: Nested <b>State</b> class that will hold all of the constants for
	 * the different game states, as well as the current game state.
	 *
	 */
	public static class State {
		public static final int MAIN_SCREEN = 0;
		public static final int LEVEL_SELECT_SCREEN = 1;
		public static final int GAME_SCREEN = 2;
		public static final int END_SCREEN = 3;
		
		public static int currentScreen;
		
		public static boolean goToGameAfterSelectLevel = false;
	}
	
	/**
	 * 
	 * @author Nathan Hoyt
	 * Date: Oct 25, 2012
	 * Desc: Nested <b>Button</b> class that will hold all of the constants for
	 * the different buttons, such as ID's and drawing methods
	 *
	 */
	public static class Button {
		public static final int START_BUTTON = 0;
		public static final int PAUSE_BUTTON = 1;
		public static final int QUIT_BUTTON = 2;
		public static final int TOWER_BUTTON = 3;
		public static final int LEVEL_SELECT_BUTTON = 4;
		public static final int RESTART_BUTTON = 5;
		public static final int BACK_BUTTON = 6;
		
		
	}
	
	/**
	 * 
	 * @author Nathan Hoyt
	 * Date: Oct 25, 2012
	 * Desc: Nested <b>Button</b> class that will hold all of the constants for
	 * the different buttons, such as ID's and drawing methods
	 *
	 */
	public static class Levels {
		public static final int MAP_HEIGHT_IN_PIXELS = 140;
		
	}
	
	public static class MouseMotion implements MouseMotionListener {

		@Override
		public void mouseDragged(MouseEvent e) {
			
		}

		@Override
		public void mouseMoved(MouseEvent e) {
			Game.mousePos = e.getPoint();
		}
	}
	
	public static class MouseListen implements MouseListener {
		
		/**
		 * Checks what screen the user is in, and sends the point
		 * on to the screen class of the current screen.
		 * @param pos
		 */
		public static void handleClick(Point pos){
			if(Game.State.currentScreen == Game.State.MAIN_SCREEN){
				MainScreen.handleClick(pos);
			} else if(Game.State.currentScreen == Game.State.LEVEL_SELECT_SCREEN){
				LevelSelectScreen.handleClick(pos);
			} else if(Game.State.currentScreen == Game.State.GAME_SCREEN){
				GameScreen.handleClick(pos);
			} else if(Game.State.currentScreen == Game.State.END_SCREEN){
				EndScreen.handleClick(pos);
			}else{
				throw new IllegalStateException("The state " + Game.State.currentScreen + " is not a valid state for the game.");
			}
		}

		@Override
		public void mouseClicked(MouseEvent arg0) {
			handleClick(arg0.getPoint());
		}

		@Override
		public void mouseEntered(MouseEvent arg0) {
		}

		@Override
		public void mouseExited(MouseEvent arg0) {
		}

		@Override
		public void mousePressed(MouseEvent arg0) {
		}

		@Override
		public void mouseReleased(MouseEvent arg0) {
		}
		
	}
}
